The security of computer systems is a topic of serious concern to almost every enterprise in today's society. Broadly speaking, there are two aspects of computer security. One aspect concerns the unwanted escape of information from the computer system to the outside world. The threat of unwanted escape of information takes several forms. In one form, hackers attempt to gain access to an enterprise's computer system to pilfer valuable information. In another form, disloyal employees or other “insiders” attempt to accomplish the same end by the access that they legitimately have. Another aspect of computer security concerns the invasion of unwanted objects, such as viruses, from the outside world into the computer system.
FIG. 1 is a schematic illustration of computer system 100. The computer system has a plurality of user stations connected to it. Computer system 100 includes communication device 102, CPU 104, memory 112 and a plurality of system resources, such as storage unit 106, printer 108 and multi-media unit 110, interconnected as shown. Computer system 100 is connected to external users via computer systems 116, 118 and 120, and via network 114.
The operating system (of computer system 100) is assumed to allow discretionary access to components of computer system 100. That is, programmers can grant or revoke user access rights to objects, such as files, directories, computer programs and the like. For this example, each external user that accesses computer system 100 via computer systems 116, 118 and 120 is allocated a different level of authorization, with respect to computer system 100. The user using computer system 116 is predetermined as a super-user, thereby being able to access and control all of the resources of computer system 100. The user using computer system 118 is predetermined as a high-level user, thereby being able to access storage unit 106, printer 108 and multi-media unit 110. The user using computer system 120 is predetermined as a low-level user, thereby being able to access printer 108.
While it is running, a computer program might be required to access objects that the user executing the program is not allowed to access. Conventionally, the administrator of a computer system can provide the computer program with predetermined enhanced privileges. This enables a non-privileged user, such as the user of system 120, to access a privileged computer-system resource in a controlled manner.
Computer system 100 is vulnerable to attack techniques that attempt to exploit enhanced privileges (e.g., gaining super-user privileges, etc.) within computer system 100 via network 114 and communication device 102. One attack technique is known as “induced buffer overflow.” Buffer overflow, a condition that is well known in the art, is caused when a computer system attempts to write past the end of a defined array. Buffer overflow can be exploited in order to gain super-user privileges, thereby providing non-authorized users with access to privileged resources. Induced buffer overflow is discussed with reference to FIGS. 2A, 2B, and 3.
As an aid to understanding the discussion of induced buffer overflow, the following background and definitions are provided.
A computer program comprises a set of instructions. Often, several instructions are grouped to form a “function.” When the instructions are executed by a computer system, a “computer-program process” is created. Conventionally, a computer-program process is the manner of execution of the computer program. A computer program process is allocated an array of user address space. User address space is a memory device wherein the computer program processes are executed.
FIG. 2A is a schematic illustration of a conventional array of user address space locations, which are generally denoted 222. User address space is organized in three regions: text region 224, stack 226, and data region 228.
Text region 224 includes text, which are machine instructions that the processor executes. The execution of text is non-linear; the flow of execution can skip text, jump to non-contiguous text locations, or call functions on certain conditions. Data region 228 is a memory space for variables and dynamic buffers. Static variables are stored in data region 228. Stack 226 is a contiguous block of memory containing data and, occasionally, executable code. Stack 226 contains and handles local variables, which are used by a function. Stack 226 also passes parameters to and from functions.
A fixed size of memory is allocated for stack 226. The amount of this memory space that is used is dynamically adjusted (by the kernel) at run time. The bottom of stack 226 is at a fixed address. Depending on the implementation, the stack will either grow “down” (i.e., towards lower memory addresses) or up (see, e.g., FIG. 2A).
FIG. 2B is a schematic illustration of stack 226 of user address space 222 that is shown in FIG. 2A.
When a computer program process is started, the computer system (e.g., computer system 100, etc.) dynamically allocates an available stack segment 232 of stack 226 to the process. The stack segment is de-allocated when the process is completed.
When a function is invoked within a process, a stack segment 234 is allocated to the computer program process. Stack segment 234 includes the information needed by a single execution of a function. This information is stored in a plurality of fields. The fields include temporary values field 246, local data field 244, return address field 242, optional access link field 240, optional control link field 238, and actual parameters field 236.
Temporary values field 246 stores the results of evaluation of expressions and local data field 244 stores data for the execution of the process. Return address field 242 includes the return address for the calling function. The return address is the computer program instruction following the function call. Optional access link field 240 points to data held in other stack segments, and optional control link field 238 and the actual parameters field 236 stores the parameters to be passed to the calling program or function. As indicated above, this stack segment (i.e., stack segment 234) is de-allocated when the function ends.
FIG. 3 is a schematic illustration of a conventional function stack segment, generally referenced 348, and of a computer program, generally referenced 356. Function stack segment 348 is equivalent to stack segment 234 of FIG. 2B.
For the example depicted in FIG. 3, computer program 356 includes three program elements 358, 360 and 362, which are performed in sequence. Program elements 358 and 362 are general computer program instructions. Program element 360 is a function call. Accordingly, function call 360 is performed after computer instruction 358 and before computer instruction 362. When function 360 is called, the flow control of the computer program 356 is altered. Typically, a function receives the computer program control, performs a predetermined task and then returns the computer program control to the statement or instruction that follows the function call.
Computer system 100 (FIG. 1) automatically determines a function return address 350, for function 360, and stores it within stack segment return-address field 242 of user address space 222 (FIGS. 2A and 2B). Function return address 350 indicates the location of the computer program instruction that follows function 360, which in the present example is instruction 362.
Induced buffer overflow is caused as follows. A string containing a computer program or other executable code is passed, as a parameter, into function stack segment 352 by function 360. The string is stored within actual parameters field 236 of function stack segment 352 (see FIG. 2B). But the length of this string exceeds the length of actual parameters field 236.
Since the string exceeds the length of actual parameters field 236, it overwrites the end of actual parameters field 236. As a consequence, the string replaces function return address 350, which is stored at return address field 242 (FIG. 2B), with initial address 354 (i.e., first address of the actual parameters field 236 of FIG. 2B) of function stack segment 352.
Initial address 354 points to the content of actual parameters field 236 (FIG. 2B) of function stack segment 352 as the next program instruction to be executed after function 360. It will be appreciated by those skilled in the art that the content of function stack segment 352 can contain a valid computer instruction, capable of performing any predetermined operation, such as granting access to any resource within system 100.
Conventionally, if the set of privileges granted to function 360 by the computer system administrator are enhanced privileges, then such privileges are granted to the computer program residing within the function stack segment 352. Users executing function 360 therefore receive such enhanced privileges (e.g., super-user privileges, etc.). In this fashion, a user is able to gain enhanced privileges without the express permission of the computer system administrator.
Several known techniques are now described for combating buffer overflow attacks.
FIG. 4 is flowchart illustrating a high-level view of a first known method for countering buffer overflow security vulnerabilities, as disclosed in published application US 2002/0144141 A1. According to FIG. 4, call processing 402 of a function call is modified to place a return address on the stack, and then a random amount of space is added to the stack. This random value is placed in a known position in the stack, or kept in a non-accessible CPU register. The rest of the stack is built normally. When return-processing 406 is called, it finds the number of bytes added to the stack and finds the return address on the stack and returns as normal.
This method lacks a means of detecting an attack, except for processor crashes. And its effectiveness is limited to a particular mode of buffer overflow attack, namely, redirecting the return stack.
FIG. 5 is a block diagram of a second known software architecture for countering buffer overflow, as disclosed in published application US 2003/0014664 A1. Generally, buffer-overflow attacks can be written so that the “nop” (no operation) part of a program stack is left out and only the return address is included after the function (executable) code part. Also a function code part can be written in a variety of ways. But in many buffer-overflow attacks, at least a small part of the return address will be present.
In this second method, a search is performed for that return address, or a small part of it (i.e., a pointer or part of it), as per operation 500. This is called a “pointer fingerprint.” The pointer fingerprint can also include, in addition to the relevant pointer, a number of other bits having no significance in the searching process. If the fingerprint is found at task 504, detection of a buffer overflow attack is reported at task 506.
This second prior-art method is therefore capable of detecting buffer overflow attacks. But this approach assumes (incorrectly) that certain critical bit-patterns will always occur in any stack buffer overflow attack.
FIG. 6 depicts a block diagram of a third software architecture for countering buffer overflow, as disclosed in published application US 2003/0014667 A1. As depicted in FIG. 6, the architecture includes a page-fault proxy handler for connection to an original page fault handler and a paging table in which supervisor flags for all entries for all writable memory pages have been initially set. The page fault proxy handler 600 comprises page fault detector 664, page fault filter 666, execution address checker 668, mitigation module 670, and controlled memory access module 672. The filter passes, to the original page fault handler 674, page faults that do not arise from an attempt to access a writable page by a user mode program. The execution address checker 668 passes, to the mitigation module 670, only those page faults arising from an attempt by a user mode program to execute from a writable page in a predetermined section of executable memory. The execution address checker 668 passes, to controlled memory access module 672, all other page faults arising from an attempt by a user mode program to access the predetermined section of executable memory. Controlled memory access module 672 permits the user program to access the writable page by changing an associated supervisor flag in the paging table.
This method detects buffer overflows, but requires modification of the operating system/software and is computer-architecture dependent.
FIG. 7 is a block diagram of a fourth known software architecture for countering buffer overflow, as disclosed in published application U.S. Pat. No. 6,301,699 B1. With reference to FIG. 7, the system performs a code disassembly procedure 702 on an input string, which includes data from the function interception. The input string is the parameter transferred by the function to the stack segment. The code disassembly procedure can be performed according to a plurality of known methods. Disassembly of the input string produces an assembly language computer program.
Next, at task 704, the system analyzes the computer program produced in the previous task to identify possible execution paths. A disassembled computer program usually includes a plurality of execution paths, which are linked by a plurality of jump instructions. A jump instruction is an instruction that specifies another instruction in the program at which execution continues. In contrast, execution after a non-jump instruction always proceeds to the following instruction within the code sequence. The disassembled code is scanned so as to determine which of the targets of each jump instruction are valid targets.
By analyzing this information and creating an execution path graph, this method attempts to determine whether the code is a valid computer program. An execution path graph records the possible execution paths according to valid jump instructions and corresponding target instructions.
Furthermore, in this method, the disassembled code is scanned so as to determine which of the jump instructions is invalid. An invalid jump instruction is one that does not end with an existing valid target instruction.
At task 708, the system analyzes the possible execution paths found to determine if the possible execution paths contain a system call. The presence of a system call indicates a likelihood of a buffer overflow attack so as to obtain super user privileges.
Next, the system determines if an attack is in progress. This is evaluated by calculating a buffer overflow score. The score is based on the number of invalid jumps detected in a previous step or if a system call is detected along one of the possible execution paths. The calculated score is compared to a threshold value that has been determined (e.g., by the system administrator, etc.) to be indicative of a buffer overflow attack. The program continues execution (task 710) or not (task 712) based on this comparison. This method provides protection against detected attacks, but not against undetected attacks.
The various prior-art software architectures discussed above do not provide protection against undetected buffer attacks. Consequently, computer systems remain vulnerable to buffer overflow attacks.